MNIST 이미지의 픽셀값은 생성자의 출력층이 tanh 활성화 함수를 포함하고 있기 때문에 (-1, 1)로 전처리 해주어야 한다.
tf.image.convert_image_dtype을 이용하면 0-255 uint8을 float32로 바꿔주면서 [0, 1] 범위로 정규화 한다.
mnist_bldr=tfds.builder('mnist')
mnist_bldr.download_and_prepare()
mnist=mnist_bldr.as_dataset(shuffle_files=False)
def preprocess(ex, mode='uniform'):
image=ex['image']
image=tf.image.convert_image_dtype(image, tf.float32)
image=tf.reshape(image, [-1])
image=image*2-1.0
if mode=='uniform':
input_z=tf.random.uniform(shape=(z_size, ), minval=-1.0, maxval=1.0)
elif mode=='normal':
input_z=tf.random.normal(shape=(z_size, ))
return input_z, image
mnist_trainset=mnist['train']
mnist_trainset=mnist_trainset.map(preprocess)
훈련 반복마다 랜덤하게 생성된 벡터 z는 생성자가 새로운 이미지를 위해 받은 입력이다.
판변자를 이미지가 입력이다.
입력 벡터 z의 배치를 생성자에 주입하면 출력 g_out을 얻는다.(가짜 샘플의 배치)
g_out을 판별자 모델에 주입하여 가짜 샘플의 배치 로짓인 d_logits_fake를 얻는다.
데이터 객체에서 가져온 전처리된 이미지를 판별자 모델에 주입하여 진짜 이미지에 대한 d_logits_real을 얻는다.
mnist_trainset=mnist_trainset.batch(32, drop_remainder=True)
input_z, input_real=next(iter(mnist_trainset))
print('input-z -- shape: ', input_z.shape)
print('input-real -- shaep: ', input_real.shape)
g_output=gen_model(input_z)
print('생성자 출력 -- 크기: ', g_output.shape)
d_logits_real=disc_model(input_real)
d_logits_fake=disc_model(g_output)
print('판별자 (가짜) -- 크기: ', d_logits_real.shape)
print('판별자 (진짜) -- 크기: ', d_logits_fake.shape)
input-z -- shape: (32, 20)
input-real -- shaep: (32, 784)
생성자 출력 -- 크기: (32, 784)
판별자 (가짜) -- 크기: (32, 1)
판별자 (진짜) -- 크기: (32, 1)
loss function
loss_fn=tf.keras.losses.BinaryCrossentropy(from_logits=True)
g_labels_real=tf.ones_like(d_logits_fake)
g_loss=loss_fn(y_true=g_labels_real, y_pred=d_logits_fake)
print('생성자 손실: {:.4f}'.format(g_loss))
d_labels_real=tf.ones_like(d_logits_real)
d_labels_fake=tf.zeros_like(d_logits_fake)
d_loss_real=loss_fn(y_true=d_labels_real, y_pred=d_logits_real)
d_loss_fake=loss_fn(y_true=d_labels_fake, y_pred=d_logits_fake)
print('판별자 손실: 진짜 {:.4f} 가짜 {:.4f}'.format(d_loss_real.numpy(), d_loss_fake.numpy()))
생성자 손실: 0.7355
판별자 손실: 진짜 1.5073 가짜 0.6583